/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bff.spi;

import com.inspur.edp.bff.api.dataprocessor.IEntityPropertyMapper;
import com.inspur.edp.bff.api.dataprocessor.MapperBEEntityInfo;
import com.inspur.edp.bff.api.dataprocessor.MapperBEPropertyInfo;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

public abstract class AbstractEntityPropertyMapper implements IEntityPropertyMapper {


    private MapperBEEntityInfo beEntityInfo;
    private Map<String, MapperBEPropertyInfo> bePropFromVO;
    private Map<String, String> voPropFromBE;
    private Map<String, IEntityPropertyMapper> mapperByBECode;
    private Map<String, IEntityPropertyMapper> mapperByVOCode;

    private static final String buildKeyByBEInfo(String beType, String prop) {
        return beType.concat(":").concat(prop);
    }

    @Override
    public MapperBEEntityInfo getBEInfo() {
        if (beEntityInfo == null) {
            beEntityInfo = buildBEInfo();
        }
        return beEntityInfo;
    }

    protected abstract MapperBEEntityInfo buildBEInfo();

    @Override
    public MapperBEPropertyInfo getBEPropertyInfoFromVO(String prop) {
        if (bePropFromVO == null) {
            buildPropertyMappings();
        }
        return bePropFromVO.get(prop);
    }

    protected final void addBEPropertyNameFromVO(String voProp, MapperBEPropertyInfo bePropInfo) {
        Objects.requireNonNull(bePropInfo, "bePropInfo");
        Objects.requireNonNull(voProp, "voProp");

        bePropFromVO.put(voProp, bePropInfo);
    }

    protected abstract void buildBEPropertyInfoFromVO();

    private void buildPropertyMappings() {
        bePropFromVO = new HashMap<>();
        buildBEPropertyInfoFromVO();
        voPropFromBE = new HashMap<>(bePropFromVO.size());
        for (Map.Entry<String, MapperBEPropertyInfo> mapping : bePropFromVO.entrySet()) {
            voPropFromBE.put(buildKeyByBEInfo(mapping.getValue().getBEType(), mapping.getValue().getBEEntityCode()), mapping.getKey());
        }
    }

    @Override
    public String getVOPropertyNameFromBE(String beType, String prop) {
        if (voPropFromBE == null) {
            buildPropertyMappings();
        }
        return voPropFromBE.get(buildKeyByBEInfo(beType, prop));
    }

    protected final void addVOPropertyNameFromBE(String beType, String prop, String voProp) {
        Objects.requireNonNull(beType, "beType");
        Objects.requireNonNull(prop, "prop");
        Objects.requireNonNull(voProp, "voProp");

        voPropFromBE.put(buildKeyByBEInfo(beType, prop), voProp);
    }

    @Override
    public IEntityPropertyMapper getMapperByBECode(String beType, String code) {
        if (mapperByBECode == null) {
            buildChildMappers();
        }

        return mapperByBECode.get(buildKeyByBEInfo(beType, code));
    }

    @Override
    public IEntityPropertyMapper getMapperByVOCode(String voCode) {
        if (mapperByVOCode == null) {
            buildChildMappers();
        }
        return mapperByVOCode.get(voCode);
    }

    protected final void addMapper(String voCode, IEntityPropertyMapper mapper) {
        Objects.requireNonNull(voCode, "voCode");
        Objects.requireNonNull(mapper, "mapper");

        mapperByVOCode.put(voCode, mapper);
    }

    protected abstract void buildMapperByVOCode();

    private void buildChildMappers() {
        mapperByVOCode = new HashMap<>();
        buildMapperByVOCode();
        mapperByVOCode.put(getVOCode(), this);
        mapperByBECode = new HashMap<>(mapperByVOCode.size());
        for (IEntityPropertyMapper mapper : mapperByVOCode.values()) {
            mapperByBECode.put(buildKeyByBEInfo(mapper.getBEInfo().getBEType(), mapper.getBEInfo().getBEEntityCode()), mapper);
        }
    }

}
